home *** CD-ROM | disk | FTP | other *** search
- /*
- * picttoppm.c -- convert a MacIntosh PICT file to PPM format.
- *
- * Copyright 1989 George Phillips
- *
- * Permission is granted to freely distribute this program in whole or in
- * part provided you don't make money off it, you don't pretend that you
- * wrote it and that this notice accompanies the code.
- *
- * George Phillips <phillips@cs.ubc.ca>
- * Department of Computer Science
- * University of British Columbia
- */
-
- #include "ppm.h"
-
- /*
- * Typical byte, 2 byte and 4 byte integers.
- */
- typedef unsigned char byte;
- typedef unsigned short word;
- typedef unsigned long longword;
-
- /*
- * Data structures for QuickDraw (and hence PICT) stuff.
- */
-
- struct Rect {
- word top;
- word left;
- word bottom;
- word right;
- };
-
- struct pixMap {
- struct Rect Bounds;
- word version;
- word packType;
- longword packSize;
- longword hRes;
- longword vRes;
- word pixelType;
- word pixelSize;
- word cmpCount;
- word cmpSize;
- longword planeBytes;
- longword pmTable;
- longword pmReserved;
- };
-
- struct ct_entry {
- word red;
- word green;
- word blue;
- };
-
- static char* stage;
- static struct Rect picFrame;
- static word* red;
- static word* green;
- static word* blue;
- static word rowlen;
- static longword planelen;
- static int verbose;
-
- struct opdef {
- char* name;
- int len;
- void (*impl)();
- char* description;
- };
-
- #define WORD_LEN (-1)
-
- static void interpret_pict ARGS(( void ));
- static void compact_plane ARGS(( word* plane, int planelen ));
- static void output_ppm ARGS(( int version ));
- static void Opcode_9A ARGS(( void ));
- static void BitsRect ARGS(( int version ));
- static void BitsRegion ARGS(( int version ));
- static void do_bitmap ARGS(( int version, int rowBytes, int is_region ));
- static void do_pixmap ARGS(( int version, word rowBytes, int is_region ));
- static void blit ARGS((
- struct Rect* srcRect, struct Rect* srcBounds, int srcwid, byte* srcplane,
- int pixSize, struct Rect* dstRect, struct Rect* dstBounds, int dstwid,
- struct ct_entry* colour_map, int mode ));
- static byte* unpackbits ARGS(( struct Rect* bounds, word rowBytes, int pixelSize ));
- static byte* expand_buf ARGS(( byte* buf, int* len, int bits_per_pixel ));
- static void Clip ARGS(( int version ));
- static void read_pixmap ARGS(( struct pixMap* p, word* rowBytes ));
- static struct ct_entry* read_colour_table ARGS(( void ));
- static void BkPixPat ARGS(( int version ));
- static void PnPixPat ARGS(( int version ));
- static void FillPixPat ARGS(( int version ));
- static void read_pattern ARGS(( void ));
-
- static void skip_text ARGS(( void ));
- static void LongText ARGS(( int version ));
- static void DHText ARGS(( int version ));
- static void DVText ARGS(( int version ));
- static void DHDVText ARGS(( int version ));
- static void skip_poly_or_region ARGS(( int version ));
- static void LongComment ARGS(( void ));
-
- static int rectsamesize ARGS(( struct Rect* r1, struct Rect* r2 ));
- static void rectinter ARGS(( struct Rect* r1, struct Rect* r2, struct Rect* r3 ));
-
- static void read_rect ARGS(( struct Rect* r ));
- static void dump_rect ARGS(( char* s, struct Rect* r ));
-
- static word get_op ARGS(( int version ));
-
- static longword read_long ARGS(( void ));
- static word read_word ARGS(( void ));
- static byte read_byte ARGS(( void ));
-
- static void skip ARGS(( int n ));
- static void read_n ARGS(( int n, char* buf ));
-
- /*
- * a table of the first 194(?) opcodes. The table is too empty.
- *
- * Probably could use an entry specifying if the opcode is valid in version
- * 1, etc.
- */
-
- /* for reserved opcodes of known length */
- #define res(length) \
- { "reserved", (length), NULL, "reserved for Apple use" }
-
- /* for reserved opcodes of length determined by a function */
- #define resf(skipfunction) \
- { "reserved", NA, (skipfunction), "reserved for Apple use" }
-
- /* seems like RGB colours are 6 bytes, but Apple say's they're variable */
- /* I'll use 6 for now as I don't care that much. */
- #define RGB_LEN (6)
-
- #define NA (0)
-
- static struct opdef optable[] = {
- /* 0x00 */ { "NOP", 0, NULL, "nop" },
- /* 0x01 */ { "Clip", NA, Clip, "clip" },
- /* 0x02 */ { "BkPat", 8, NULL, "background pattern" },
- /* 0x03 */ { "TxFont", 2, NULL, "text font (word)" },
- /* 0x04 */ { "TxFace", 1, NULL, "text face (byte)" },
- /* 0x05 */ { "TxMode", 2, NULL, "text mode (word)" },
- /* 0x06 */ { "SpExtra", 4, NULL, "space extra (fixed point)" },
- /* 0x07 */ { "PnSize", 4, NULL, "pen size (point)" },
- /* 0x08 */ { "PnMode", 2, NULL, "pen mode (word)" },
- /* 0x09 */ { "PnPat", 8, NULL, "pen pattern" },
- /* 0x0a */ { "FillPat", 8, NULL, "fill pattern" },
- /* 0x0b */ { "OvSize", 4, NULL, "oval size (point)" },
- /* 0x0c */ { "Origin", 4, NULL, "dh, dv (word)" },
- /* 0x0d */ { "TxSize", 2, NULL, "text size (word)" },
- /* 0x0e */ { "FgColor", 4, NULL, "foreground color (longword)" },
- /* 0x0f */ { "BkColor", 4, NULL, "background color (longword)" },
- /* 0x10 */ { "TxRatio", 8, NULL, "numer (point), denom (point)" },
- /* 0x11 */ { "Version", 1, NULL, "version (byte)" },
- /* 0x12 */ { "BkPixPat", NA, BkPixPat, "color background pattern" },
- /* 0x13 */ { "PnPixPat", NA, PnPixPat, "color pen pattern" },
- /* 0x14 */ { "FillPixPat", NA, FillPixPat, "color fill pattern" },
- /* 0x15 */ { "PnLocHFrac", 2, NULL, "fractional pen position" },
- /* 0x16 */ { "ChExtra", 2, NULL, "extra for each character" },
- /* 0x17 */ res(0),
- /* 0x18 */ res(0),
- /* 0x19 */ res(0),
- /* 0x1a */ { "RGBFgCol", RGB_LEN, NULL, "RGB foreColor" },
- /* 0x1b */ { "RGBBkCol", RGB_LEN, NULL, "RGB backColor" },
- /* 0x1c */ { "HiliteMode", 0, NULL, "hilite mode flag" },
- /* 0x1d */ { "HiliteColor", RGB_LEN, NULL, "RGB hilite color" },
- /* 0x1e */ { "DefHilite", 0, NULL, "Use default hilite color" },
- /* 0x1f */ { "OpColor", RGB_LEN, NULL, "RGB OpColor for arithmetic modes" },
- /* 0x20 */ { "Line", 8, NULL, "pnLoc (point), newPt (point)" },
- /* 0x21 */ { "LineFrom", 4, NULL, "newPt (point)" },
- /* 0x22 */ { "ShortLine", 6, NULL, "pnLoc (point, dh, dv (-128 .. 127))" },
- /* 0x23 */ { "ShortLineFrom", 2, NULL, "dh, dv (-128 .. 127)" },
- /* 0x24 */ res(WORD_LEN),
- /* 0x25 */ res(WORD_LEN),
- /* 0x26 */ res(WORD_LEN),
- /* 0x27 */ res(WORD_LEN),
- /* 0x28 */ { "LongText", NA, LongText, "txLoc (point), count (0..255), text" },
- /* 0x29 */ { "DHText", NA, DHText, "dh (0..255), count (0..255), text" },
- /* 0x2a */ { "DVText", NA, DVText, "dv (0..255), count (0..255), text" },
- /* 0x2b */ { "DHDVText", NA, DHDVText, "dh, dv (0..255), count (0..255), text" },
- /* 0x2c */ res(WORD_LEN),
- /* 0x2d */ res(WORD_LEN),
- /* 0x2e */ res(WORD_LEN),
- /* 0x2f */ res(WORD_LEN),
- /* 0x30 */ { "frameRect", 8, NULL, "rect" },
- /* 0x31 */ { "paintRect", 8, NULL, "rect" },
- /* 0x32 */ { "eraseRect", 8, NULL, "rect" },
- /* 0x33 */ { "invertRect", 8, NULL, "rect" },
- /* 0x34 */ { "fillRect", 8, NULL, "rect" },
- /* 0x35 */ res(8),
- /* 0x36 */ res(8),
- /* 0x37 */ res(8),
- /* 0x38 */ { "frameSameRect", 0, NULL, "rect" },
- /* 0x39 */ { "paintSameRect", 0, NULL, "rect" },
- /* 0x3a */ { "eraseSameRect", 0, NULL, "rect" },
- /* 0x3b */ { "invertSameRect", 0, NULL, "rect" },
- /* 0x3c */ { "fillSameRect", 0, NULL, "rect" },
- /* 0x3d */ res(0),
- /* 0x3e */ res(0),
- /* 0x3f */ res(0),
- /* 0x40 */ { "frameRRect", 8, NULL, "rect" },
- /* 0x41 */ { "paintRRect", 8, NULL, "rect" },
- /* 0x42 */ { "eraseRRect", 8, NULL, "rect" },
- /* 0x43 */ { "invertRRect", 8, NULL, "rect" },
- /* 0x44 */ { "fillRRrect", 8, NULL, "rect" },
- /* 0x45 */ res(8),
- /* 0x46 */ res(8),
- /* 0x47 */ res(8),
- /* 0x48 */ { "frameSameRRect", 0, NULL, "rect" },
- /* 0x49 */ { "paintSameRRect", 0, NULL, "rect" },
- /* 0x4a */ { "eraseSameRRect", 0, NULL, "rect" },
- /* 0x4b */ { "invertSameRRect", 0, NULL, "rect" },
- /* 0x4c */ { "fillSameRRect", 0, NULL, "rect" },
- /* 0x4d */ res(0),
- /* 0x4e */ res(0),
- /* 0x4f */ res(0),
- /* 0x50 */ { "frameOval", 8, NULL, "rect" },
- /* 0x51 */ { "paintOval", 8, NULL, "rect" },
- /* 0x52 */ { "eraseOval", 8, NULL, "rect" },
- /* 0x53 */ { "invertOval", 8, NULL, "rect" },
- /* 0x54 */ { "fillOval", 8, NULL, "rect" },
- /* 0x55 */ res(8),
- /* 0x56 */ res(8),
- /* 0x57 */ res(8),
- /* 0x58 */ { "frameSameOval", 0, NULL, "rect" },
- /* 0x59 */ { "paintSameOval", 0, NULL, "rect" },
- /* 0x5a */ { "eraseSameOval", 0, NULL, "rect" },
- /* 0x5b */ { "invertSameOval", 0, NULL, "rect" },
- /* 0x5c */ { "fillSameOval", 0, NULL, "rect" },
- /* 0x5d */ res(0),
- /* 0x5e */ res(0),
- /* 0x5f */ res(0),
- /* 0x60 */ { "frameArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x61 */ { "paintArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x62 */ { "eraseArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x63 */ { "invertArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x64 */ { "fillArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x65 */ res(12),
- /* 0x66 */ res(12),
- /* 0x67 */ res(12),
- /* 0x68 */ { "frameSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x69 */ { "paintSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6a */ { "eraseSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6b */ { "invertSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6c */ { "fillSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6d */ res(4),
- /* 0x6e */ res(4),
- /* 0x6f */ res(4),
- /* 0x70 */ { "framePoly", NA, skip_poly_or_region, "poly" },
- /* 0x71 */ { "paintPoly", NA, skip_poly_or_region, "poly" },
- /* 0x72 */ { "erasePoly", NA, skip_poly_or_region, "poly" },
- /* 0x73 */ { "invertPoly", NA, skip_poly_or_region, "poly" },
- /* 0x74 */ { "fillPoly", NA, skip_poly_or_region, "poly" },
- /* 0x75 */ resf(skip_poly_or_region),
- /* 0x76 */ resf(skip_poly_or_region),
- /* 0x77 */ resf(skip_poly_or_region),
- /* 0x78 */ { "frameSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x79 */ { "paintSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7a */ { "eraseSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7b */ { "invertSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7c */ { "fillSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7d */ res(0),
- /* 0x7e */ res(0),
- /* 0x7f */ res(0),
- /* 0x80 */ { "frameRgn", NA, skip_poly_or_region, "region" },
- /* 0x81 */ { "paintRgn", NA, skip_poly_or_region, "region" },
- /* 0x82 */ { "eraseRgn", NA, skip_poly_or_region, "region" },
- /* 0x83 */ { "invertRgn", NA, skip_poly_or_region, "region" },
- /* 0x84 */ { "fillRgn", NA, skip_poly_or_region, "region" },
- /* 0x85 */ resf(skip_poly_or_region),
- /* 0x86 */ resf(skip_poly_or_region),
- /* 0x87 */ resf(skip_poly_or_region),
- /* 0x88 */ { "frameSameRgn", 0, NULL, "region (NYI)" },
- /* 0x89 */ { "paintSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8a */ { "eraseSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8b */ { "invertSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8c */ { "fillSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8d */ res(0),
- /* 0x8e */ res(0),
- /* 0x8f */ res(0),
- /* 0x90 */ { "BitsRect", NA, BitsRect, "copybits, rect clipped" },
- /* 0x91 */ { "BitsRgn", NA, BitsRegion, "copybits, rgn clipped" },
- /* 0x92 */ res(WORD_LEN),
- /* 0x93 */ res(WORD_LEN),
- /* 0x94 */ res(WORD_LEN),
- /* 0x95 */ res(WORD_LEN),
- /* 0x96 */ res(WORD_LEN),
- /* 0x97 */ res(WORD_LEN),
- /* 0x98 */ { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" },
- /* 0x99 */ { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" },
- /* 0x9a */ { "Opcode_9A", NA, Opcode_9A, "the mysterious opcode 9A" },
- /* 0x9b */ res(WORD_LEN),
- /* 0x9c */ res(WORD_LEN),
- /* 0x9d */ res(WORD_LEN),
- /* 0x9e */ res(WORD_LEN),
- /* 0x9f */ res(WORD_LEN),
- /* 0xa0 */ { "ShortComment", 2, NULL, "kind (word)" },
- /* 0xa1 */ { "LongComment", NA, LongComment, "kind (word), size (word), data" }
- };
-
- static int align = 0;
- static FILE* ifp;
-
- void
- main(argc, argv)
- int argc;
- char* argv[];
- {
- int argn;
- char* usage = "[-verbose] [pictfile]";
-
- ppm_init( &argc, argv );
-
- argn = 1;
- verbose = 0;
-
- if (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
- if (pm_keymatch(argv[argn], "-verbose", 2))
- verbose = 1;
- else
- pm_usage(usage);
- ++argn;
- }
-
- if (argn < argc) {
- ifp = pm_openr(argv[argn]);
- ++argn;
- } else
- ifp = stdin;
-
- if (argn != argc)
- pm_usage(usage);
-
- stage = "Reading 512 byte header";
- skip(512);
-
- interpret_pict();
- exit(0);
- }
-
- static void
- interpret_pict()
- {
- byte ch;
- word picSize;
- word opcode;
- word len;
- int version;
-
- stage = "Reading picture size";
- picSize = read_word();
-
- if (verbose)
- pm_message("picture size = %d (0x%x)", picSize, picSize);
-
- stage = "reading picture frame";
- read_rect(&picFrame);
-
- if (verbose) {
- dump_rect("Picture frame:", &picFrame);
- pm_message("Picture size is %d x %d",
- picFrame.right - picFrame.left,
- picFrame.bottom - picFrame.top);
- }
-
- /* allocation is same for version 1 or version 2. We are super-duper
- * wasteful of memory for version 1 picts. Someday, we'll separate
- * things and only allocate a byte per pixel for version 1 (or heck,
- * even only a bit, but that would require even more extra work).
- */
-
- rowlen = picFrame.right - picFrame.left;
- planelen = rowlen * (picFrame.bottom - picFrame.top);
- if ((red = (word*)malloc(planelen * sizeof(word))) == NULL ||
- (green = (word*)malloc(planelen * sizeof(word))) == NULL ||
- (blue = (word*)malloc(planelen * sizeof(word))) == NULL)
-
- pm_error("not enough memory to hold picture");
-
- while ((ch = read_byte()) == 0)
- ;
- if (ch != 0x11)
- pm_error("No version number");
-
- switch (read_byte()) {
- case 1:
- version = 1;
- break;
- case 2:
- if (read_byte() != 0xff)
- pm_error("can only do version 2, subcode 0xff");
- version = 2;
- break;
- default:
- pm_error("Unknown version");
- }
-
- if (verbose)
- pm_message("PICT version %d", version);
-
- while((opcode = get_op(version)) != 0xff) {
- if (opcode < 0xa2) {
- if (verbose) {
- stage = optable[opcode].name;
- if (!strcmp(stage, "reserved"))
- pm_message("reserved opcode=0x%x", opcode);
- else
- pm_message("%s", stage = optable[opcode].name);
- }
-
- if (optable[opcode].impl != NULL)
- (*optable[opcode].impl)(version);
- else if (optable[opcode].len >= 0)
- skip(optable[opcode].len);
- else switch (optable[opcode].len) {
- case WORD_LEN:
- len = read_word();
- skip(len);
- break;
- default:
- pm_error("can't do length of %d",
- optable[opcode].len);
- }
- }
- else if (opcode == 0xc00) {
- if (verbose)
- pm_message("HeaderOp");
- stage = "HeaderOp";
- skip(24);
- }
- else if (opcode >= 0xa2 && opcode <= 0xaf) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode);
- skip(read_word());
- }
- else if (opcode >= 0xb0 && opcode <= 0xcf) {
- /* just a reserved opcode, no data */
- if (verbose)
- pm_message("reserved 0x%x", opcode);
- }
- else if (opcode >= 0xd0 && opcode <= 0xfe) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode);
- skip(read_long());
- }
- else if (opcode >= 0x100 && opcode <= 0x7fff) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode);
- skip((opcode >> 7) & 255);
- }
- else if (opcode >= 0x8000 && opcode <= 0x80ff) {
- /* just a reserved opcode */
- if (verbose)
- pm_message("reserved 0x%x", opcode);
- }
- else if (opcode >= 8100 && opcode <= 0xffff) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode);
- skip(read_long());
- }
- else
- pm_error("can't handle opcode of %x", opcode);
- }
- output_ppm(version);
- }
-
- static void
- compact_plane(plane, planelen)
- register word* plane;
- register int planelen;
- {
- register byte* p;
-
- for (p = (byte*)plane; planelen-- > 0; )
- *p++ = (*plane++ >> 8) & 255;
- }
-
- static void
- output_ppm(version)
- int version;
- {
- int width;
- int height;
- word test;
- int offset1;
- register char* r;
- register char* g;
- register char* b;
- pixel* pixelrow;
- register pixel* pP;
- int row;
- register int col;
-
- /* determine byte order */
- test = 0x0001;
- offset1 = *((char*)&test);
-
- stage = "writing PPM";
-
- width = picFrame.right - picFrame.left;
- height = picFrame.bottom - picFrame.top;
- r = (char*) red;
- compact_plane((word*) r, width * height);
- g = (char*) green;
- compact_plane((word*) g, width * height);
- b = (char*) blue;
- compact_plane((word*) b, width * height);
-
- ppm_writeppminit(stdout, width, height, (pixval) 255, 0 );
- pixelrow = ppm_allocrow(width);
- for (row = 0; row < height; ++row) {
- for (col = 0, pP = pixelrow; col < width;
- ++col, ++pP, ++r, ++g, ++b) {
- PPM_ASSIGN(*pP, *r, *g, *b);
- }
-
- ppm_writeppmrow(stdout, pixelrow, width, (pixval) 255, 0 );
- }
- pm_close(stdout);
- }
-
- /*
- * This could use read_pixmap, but I'm too lazy to hack read_pixmap.
- */
-
- static void
- Opcode_9A()
- {
- #ifdef DUMP
- FILE *fp = fopen("data", "w");
- int ch;
- if (fp == NULL) exit(1);
- while ((ch = fgetc(ifp)) != EOF) fputc(ch, fp);
- exit(0);
- #else
- struct pixMap p;
- struct Rect srcRect;
- struct Rect dstRect;
- byte* pm;
- int pixwidth;
- word mode;
-
- /* skip fake len, and fake EOF */
- skip(4);
- read_word(); /* version */
- read_rect(&p.Bounds);
- pixwidth = p.Bounds.right - p.Bounds.left;
- p.packType = read_word();
- p.packSize = read_long();
- p.hRes = read_long();
- p.vRes = read_long();
- p.pixelType = read_word();
- p.pixelSize = read_word();
- p.pixelSize = read_word();
- p.cmpCount = read_word();
- p.cmpSize = read_word();
- p.planeBytes = read_long();
- p.pmTable = read_long();
- p.pmReserved = read_long();
-
- if (p.pixelSize == 16)
- pixwidth *= 2;
- else if (p.pixelSize == 32)
- pixwidth *= 3;
-
- read_rect(&srcRect);
- if (verbose)
- dump_rect("source rectangle:", &srcRect);
-
- read_rect(&dstRect);
- if (verbose)
- dump_rect("destination rectangle:", &dstRect);
-
- mode = read_word();
- if (verbose)
- pm_message("mode = %x", mode);
-
- pm = unpackbits(&p.Bounds, 0, p.pixelSize);
-
- blit(&srcRect, &(p.Bounds), pixwidth, pm, p.pixelSize,
- &dstRect, &picFrame, rowlen,
- NULL,
- mode);
-
- free(pm);
- #endif
- }
-
- static void
- BitsRect(version)
- int version;
- {
- word rowBytes;
-
- stage = "Reading rowBytes for bitsrect";
- rowBytes = read_word();
-
- if (verbose)
- pm_message("rowbytes = 0x%x (%d)", rowBytes, rowBytes & 0x7fff);
-
- if (rowBytes & 0x8000)
- do_pixmap(version, rowBytes, 0);
- else
- do_bitmap(version, rowBytes, 0);
- }
-
- static void
- BitsRegion(version)
- int version;
- {
- word rowBytes;
-
- stage = "Reading rowBytes for bitsregion";
- rowBytes = read_word();
-
- if (rowBytes & 0x8000)
- do_pixmap(version, rowBytes, 1);
- else
- do_bitmap(version, rowBytes, 1);
- }
-
- static void
- do_bitmap(version, rowBytes, is_region)
- int version;
- int rowBytes;
- int is_region;
- {
- struct Rect Bounds;
- struct Rect srcRect;
- struct Rect dstRect;
- word mode;
- byte* pm;
- static struct ct_entry colour_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} };
-
- read_rect(&Bounds);
- read_rect(&srcRect);
- read_rect(&dstRect);
- mode = read_word();
-
- if (is_region)
- skip_poly_or_region(version);
-
- stage = "unpacking rectangle";
-
- pm = unpackbits(&Bounds, rowBytes, 1);
-
- blit(&srcRect, &Bounds, Bounds.right - Bounds.left, pm, 8,
- &dstRect, &picFrame, rowlen,
- colour_table,
- mode);
-
- free(pm);
- }
-
- #if __STDC__
- static void
- do_pixmap( int version, word rowBytes, int is_region )
- #else /*__STDC__*/
- static void
- do_pixmap(version, rowBytes, is_region)
- int version;
- word rowBytes;
- int is_region;
- #endif /*__STDC__*/
- {
- word mode;
- struct pixMap p;
- word pixwidth;
- byte* pm;
- struct ct_entry* colour_table;
- struct Rect srcRect;
- struct Rect dstRect;
-
- read_pixmap(&p, NULL);
-
- pixwidth = p.Bounds.right - p.Bounds.left;
-
- if (verbose)
- pm_message("%d x %d rectangle", pixwidth,
- p.Bounds.bottom - p.Bounds.top);
-
- colour_table = read_colour_table();
-
- read_rect(&srcRect);
-
- if (verbose)
- dump_rect("source rectangle:", &srcRect);
-
- read_rect(&dstRect);
-
- if (verbose)
- dump_rect("destination rectangle:", &dstRect);
-
- mode = read_word();
-
- if (verbose)
- pm_message("mode = %x", mode);
-
- if (is_region)
- skip_poly_or_region(version);
-
- stage = "unpacking rectangle";
-
- pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
-
- blit(&srcRect, &(p.Bounds), pixwidth, pm, 8,
- &dstRect, &picFrame, rowlen,
- colour_table,
- mode);
-
- free(colour_table);
- free(pm);
- }
-
- static void
- blit(srcRect, srcBounds, srcwid, srcplane, pixSize, dstRect, dstBounds, dstwid, colour_map, mode)
- struct Rect* srcRect;
- struct Rect* srcBounds;
- int srcwid;
- byte* srcplane;
- int pixSize;
- struct Rect* dstRect;
- struct Rect* dstBounds;
- int dstwid;
- struct ct_entry* colour_map;
- int mode;
- {
- struct Rect clipsrc;
- struct Rect clipdst;
- register byte* src;
- register word* reddst;
- register word* greendst;
- register word* bluedst;
- register int i;
- register int j;
- int dstoff;
- int xsize;
- int ysize;
- int srcadd;
- int dstadd;
- struct ct_entry* ct;
- int pkpixsize;
-
- /* almost got it. clip source rect with source bounds.
- * clip dest rect with dest bounds.
- * If they're not the same size - die!
- * (it would require zeroing some area!)
- * co-ordinate translations are actually done!
- */
- rectinter(srcBounds, srcRect, &clipsrc);
- rectinter(dstBounds, dstRect, &clipdst);
-
- if (verbose) {
- dump_rect("copying from:", &clipsrc);
- dump_rect("to: ", &clipdst);
- }
-
- if (!rectsamesize(&clipsrc, &clipdst))
- pm_message("warning, rectangles of different sizes after clipping!");
-
-
- /* lots of assumptions about 8 bits per component, chunky bits, etc! */
- /* :-( :-( */
-
- pkpixsize = 1;
- if (pixSize == 16)
- pkpixsize = 2;
-
- src = srcplane + (clipsrc.top - srcBounds->top) * srcwid +
- (clipsrc.left - srcBounds->left) * pkpixsize;
- dstoff = (clipdst.top - dstBounds->top) * dstwid +
- (clipdst.left - dstBounds->left);
-
- reddst = red + dstoff;
- greendst = green + dstoff;
- bluedst = blue + dstoff;
-
- xsize = clipsrc.right - clipsrc.left;
- ysize = clipsrc.bottom - clipsrc.top;
- srcadd = srcwid - xsize * pkpixsize;
- dstadd = dstwid - xsize;
-
- switch (pixSize) {
- case 8:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- ct = colour_map + *src++;
- *reddst++ = ct->red;
- *greendst++ = ct->green;
- *bluedst++ = ct->blue;
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 16:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- *reddst++ = (*src & 0x7c) << 9;
- *greendst = (*src++ & 3) << 14;
- *greendst++ |= (*src & 0xe0) << 6;
- *bluedst++ = (*src++ & 0x1f) << 11;
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 32:
- srcadd = (srcwid / 3) - xsize;
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j)
- *reddst++ = *src++ << 8;
-
- reddst += dstadd;
- src += srcadd;
-
- for (j = 0; j < xsize; ++j)
- *greendst++ = *src++ << 8;
-
- greendst += dstadd;
- src += srcadd;
-
- for (j = 0; j < xsize; ++j)
- *bluedst++ = *src++ << 8;
-
- bluedst += dstadd;
- src += srcadd;
- }
- }
- }
-
- #if __STDC__
- static byte*
- unpackbits( struct Rect* bounds, word rowBytes, int pixelSize )
- #else /*__STDC__*/
- static byte*
- unpackbits(bounds, rowBytes, pixelSize)
- struct Rect* bounds;
- word rowBytes;
- int pixelSize;
- #endif /*__STDC__*/
- {
- byte* linebuf;
- byte* pm;
- byte* pm_ptr;
- register int i,j,k,l;
- word pixwidth;
- int linelen;
- int len;
- byte* bytepixels;
- int buflen;
- int pkpixsize;
-
- if (pixelSize <= 8)
- rowBytes &= 0x7fff;
-
- stage = "unpacking packbits";
-
- pixwidth = bounds->right - bounds->left;
-
- pkpixsize = 1;
- if (pixelSize == 16) {
- pkpixsize = 2;
- pixwidth *= 2;
- }
- else if (pixelSize == 32)
- pixwidth *= 3;
-
- if (rowBytes == 0)
- rowBytes = pixwidth;
-
- /* we're sloppy and allocate some extra space because we can overshoot
- * by as many as 8 bytes when we unpack the raster lines. Really, I
- * should be checking to see if we go over the scan line (it is
- * possbile) and complain of a corrupt file. That fix is more complex
- * (and probably costly in CPU cycles) and will have to come later.
- */
- if ((pm = (byte*)malloc((pixwidth * (bounds->bottom - bounds->top) + 8) * sizeof(byte))) == NULL)
- pm_error("no mem for packbits rectangle");
-
- /* Sometimes we get rows with length > rowBytes. I'll allocate some
- * extra for slop and only die if the size is _way_ out of wack.
- */
- if ((linebuf = (byte*)malloc(rowBytes + 100)) == NULL)
- pm_error("can't allocate memory for line buffer");
-
- if (rowBytes < 8) {
- /* ah-ha! The bits aren't actually packed. This will be easy */
- for (i = 0; i < bounds->bottom - bounds->top; i++) {
- pm_ptr = pm + i * pixwidth;
- read_n(buflen = rowBytes, (char*) linebuf);
- bytepixels = expand_buf(linebuf, &buflen, pixelSize);
- for (j = 0; j < buflen; j++)
- *pm_ptr++ = *bytepixels++;
- }
- }
- else {
- for (i = 0; i < bounds->bottom - bounds->top; i++) {
- pm_ptr = pm + i * pixwidth;
- if (rowBytes > 250 || pixelSize > 8)
- linelen = read_word();
- else
- linelen = read_byte();
-
- if (verbose)
- pm_message("linelen: %d", linelen);
-
- if (linelen > rowBytes) {
- pm_message("linelen > rowbytes! (%d > %d) at line %d",
- linelen, rowBytes, i);
- }
-
- read_n(linelen, (char*) linebuf);
-
- for (j = 0; j < linelen; ) {
- if (linebuf[j] & 0x80) {
- len = ((linebuf[j] ^ 255) & 255) + 2;
- buflen = pkpixsize;
- bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
- for (k = 0; k < len; k++) {
- for (l = 0; l < buflen; l++)
- *pm_ptr++ = *bytepixels++;
- bytepixels -= buflen;
- }
- j += 1 + pkpixsize;
- }
- else {
- len = (linebuf[j] & 255) + 1;
- buflen = len * pkpixsize;
- bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
- for (k = 0; k < buflen; k++)
- *pm_ptr++ = *bytepixels++;
- j += len * pkpixsize + 1;
- }
- }
- }
- }
-
- free(linebuf);
-
- return(pm);
- }
-
- static byte*
- expand_buf(buf, len, bits_per_pixel)
- byte* buf;
- int* len;
- int bits_per_pixel;
- {
- static byte pixbuf[256 * 8];
- register byte* src;
- register byte* dst;
- register int i;
-
- src = buf;
- dst = pixbuf;
-
- switch (bits_per_pixel) {
- case 8:
- case 16:
- case 32:
- return(buf);
- case 4:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 4) & 15;
- *dst++ = *src++ & 15;
- }
- *len *= 2;
- break;
- case 2:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 6) & 3;
- *dst++ = (*src >> 4) & 3;
- *dst++ = (*src >> 2) & 3;
- *dst++ = *src++ & 3;
- }
- *len *= 4;
- break;
- case 1:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 7) & 1;
- *dst++ = (*src >> 6) & 1;
- *dst++ = (*src >> 5) & 1;
- *dst++ = (*src >> 4) & 1;
- *dst++ = (*src >> 3) & 1;
- *dst++ = (*src >> 2) & 1;
- *dst++ = (*src >> 1) & 1;
- *dst++ = *src++ & 1;
- }
- *len *= 8;
- break;
- default:
- pm_error("bad bits per pixel in expand_buf");
- }
- return(pixbuf);
- }
-
- static void
- Clip(version)
- int version;
- {
- skip(read_word() - 2);
- }
-
- static void
- read_pixmap(p, rowBytes)
- struct pixMap* p;
- word* rowBytes;
- {
- stage = "getting pixMap header";
-
- if (rowBytes != NULL)
- *rowBytes = read_word();
-
- read_rect(&p->Bounds);
- p->version = read_word();
- p->packType = read_word();
- p->packSize = read_long();
- p->hRes = read_long();
- p->vRes = read_long();
- p->pixelType = read_word();
- p->pixelSize = read_word();
- p->cmpCount = read_word();
- p->cmpSize = read_word();
- p->planeBytes = read_long();
- p->pmTable = read_long();
- p->pmReserved = read_long();
-
- if (verbose) {
- pm_message("pixelType: %d", p->pixelType);
- pm_message("pixelSize: %d", p->pixelSize);
- pm_message("cmpCount: %d", p->cmpCount);
- pm_message("cmpSize: %d", p->cmpSize);
- }
-
- if (p->pixelType != 0)
- pm_error("sorry, I only do chunky format");
- if (p->cmpCount != 1)
- pm_error("sorry, cmpCount != 1");
- if (p->pixelSize != p->cmpSize)
- pm_error("oops, pixelSize != cmpSize");
- }
-
- static struct ct_entry*
- read_colour_table()
- {
- longword ctSeed;
- word ctFlags;
- word ctSize;
- word val;
- int i;
- struct ct_entry* colour_table;
-
- stage = "getting color table info";
-
- ctSeed = read_long();
- ctFlags = read_word();
- ctSize = read_word();
-
- if (verbose) {
- pm_message("ctSeed: %d", ctSeed);
- pm_message("ctFlags: %d", ctFlags);
- pm_message("ctSize: %d", ctSize);
- }
-
- stage = "reading colour table";
-
- if ((colour_table = (struct ct_entry*) malloc(sizeof(struct ct_entry) * (ctSize + 1))) == NULL)
- pm_error("no memory for colour table");
-
- for (i = 0; i <= ctSize; i++) {
- if ((val = read_word()) > ctSize)
- pm_error("pixel value greater than colour table size");
- /* seems that if we have a device colour table, the val is
- * always zero, so I assume we allocate up the list of colours.
- */
- if (ctFlags & 0x8000)
- val = i;
- colour_table[val].red = read_word();
- colour_table[val].green = read_word();
- colour_table[val].blue = read_word();
-
- if (verbose)
- pm_message("%d: [%d,%d,%d]", val,
- colour_table[val].red,
- colour_table[val].green,
- colour_table[val].blue, 0);
- }
-
- return(colour_table);
- }
-
- /* these 3 do nothing but skip over their data! */
- static void
- BkPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- static void
- PnPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- static void
- FillPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- /* this just skips over a version 2 pattern. Probabaly will return
- * a pattern in the fabled complete version.
- */
- static void
- read_pattern()
- {
- word PatType;
- word rowBytes;
- struct pixMap p;
- byte* pm;
- struct ct_entry* ct;
-
- stage = "Reading a pattern";
-
- PatType = read_word();
-
- switch (PatType) {
- case 2:
- skip(8); /* old pattern data */
- skip(5); /* RGB for pattern */
- break;
- case 1:
- skip(8); /* old pattern data */
- read_pixmap(&p, &rowBytes);
- ct = read_colour_table();
- pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
- free(pm);
- free(ct);
- break;
- default:
- pm_error("unknown pattern type in read_pattern");
- }
- }
-
- /* more stubs for text output */
-
- static void
- skip_text()
- {
- skip(read_byte());
- }
-
- static void
- LongText(version)
- int version;
- {
- skip(4);
- skip_text();
- }
-
- static void
- DHText(version)
- int version;
- {
- skip(1);
- skip_text();
- }
-
- static void
- DVText(version)
- int version;
- {
- skip(1);
- skip_text();
- }
-
- static void
- DHDVText(version)
- int version;
- {
- skip(2);
- skip_text();
- }
-
- static void
- skip_poly_or_region(version)
- int version;
- {
- stage = "skipping polygon or region";
- skip(read_word() - 2);
- }
-
- static void
- LongComment()
- {
- stage = "skipping longword comment";
-
- skip(2);
- skip(read_word());
- }
-
- static int
- rectequal(r1, r2)
- struct Rect* r1;
- struct Rect* r2;
- {
- return(r1->top == r2->top &&
- r1->bottom == r2->bottom &&
- r1->left == r2->left &&
- r1->right == r2->right);
- }
-
- static int
- rectsamesize(r1, r2)
- struct Rect* r1;
- struct Rect* r2;
- {
- return(r1->right - r1->left == r2->right - r2->left &&
- r1->bottom - r1->top == r2->bottom - r2->top);
- }
-
- static void
- rectinter(r1, r2, r3)
- struct Rect* r1;
- struct Rect* r2;
- struct Rect* r3;
- {
- r3->left = max(r1->left, r2->left);
- r3->top = max(r1->top, r2->top);
- r3->right = min(r1->right, r2->right);
- r3->bottom = min(r1->bottom, r2->bottom);
- }
-
- static void
- read_rect(r)
- struct Rect* r;
- {
- r->top = read_word();
- r->left = read_word();
- r->bottom = read_word();
- r->right = read_word();
- }
-
- static void
- dump_rect(s, r)
- char* s;
- struct Rect* r;
- {
- pm_message("%s (%d,%d) (%d,%d)",
- s, r->left, r->top, r->right, r->bottom);
- }
-
- /*
- * All data in version 2 is 2-byte word aligned. Odd size data
- * is padded with a null.
- */
- static word
- get_op(version)
- int version;
- {
- if ((align & 1) && version == 2) {
- stage = "aligning for opcode";
- read_byte();
- }
-
- stage = "reading opcode";
-
- if (version == 1)
- return(read_byte());
- else
- return(read_word());
- }
-
- static longword
- read_long()
- {
- word i;
-
- i = read_word();
- return((i << 16) | read_word());
- }
-
- static word
- read_word()
- {
- byte b;
-
- b = read_byte();
-
- return((b << 8) | read_byte());
- }
-
- static byte
- read_byte()
- {
- int c;
-
- if ((c = fgetc(ifp)) == EOF)
- pm_error("EOF / read error while %s", stage);
-
- ++align;
- return(c & 255);
- }
-
- static void
- skip(n)
- int n;
- {
- static byte buf[1024];
-
- align += n;
-
- for (; n > 0; n -= 1024)
- if (fread(buf, n > 1024 ? 1024 : n, 1, ifp) != 1)
- pm_error("EOF / read error while %s", stage);
- }
-
- static void
- read_n(n, buf)
- int n;
- char* buf;
- {
- align += n;
-
- if (fread(buf, n, 1, ifp) != 1)
- pm_error("EOF / read error while %s", stage);
- }
-